package com.rtx.edi.platform.baseinfo.service.impl;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rtx.edi.model.api.bo.ApiMappingInfoBo;
import com.rtx.edi.model.api.po.PlApiMapping;
import com.rtx.edi.model.api.po.PlApiMappingStructure;
import com.rtx.edi.model.apibaseinfo.po.PlApibaseinfo;
import com.rtx.edi.model.application.po.PlApplicationEnvironment;
import com.rtx.edi.model.application.po.PlApplicationLink;
import com.rtx.edi.model.application.po.PlApplicationLinkDtl;
import com.rtx.edi.model.express.po.PlExpressApiConfig;
import com.rtx.edi.model.log.po.PlApiRequestLog;
import com.rtx.edi.model.request.SyncRequest;
import com.rtx.edi.platform.application.mapper.PlApplicationEnvironmentMapper;
import com.rtx.edi.platform.application.mapper.PlApplicationLinkDtlMapper;
import com.rtx.edi.platform.application.mapper.PlApplicationLinkMapper;
import com.rtx.edi.platform.baseinfo.mapper.PlApibaseinfoMapper;
import com.rtx.edi.platform.baseinfo.service.PlApiService;
import com.rtx.edi.platform.express.config.mapper.PlExpressApiConfigMapper;
import com.rtx.edi.platform.mapping.mapper.PlApiMappingMapper;
import com.rtx.edi.platform.structure.mapper.PlApiMappingStructureMapper;

/**
 * api服务 服务实现类
 */
@Service
public class PlApiServiceImpl implements PlApiService {

    @Autowired
    private PlApibaseinfoMapper plApibaseinfoMapper;

    @Autowired
    private PlApiMappingMapper plApiMappingMapper;

    @Autowired
    private PlApplicationLinkMapper plApplicationLinkMapper;

    @Autowired
    private PlApplicationLinkDtlMapper plApplicationLinkDtlMapper;

    @Autowired
    private PlApplicationEnvironmentMapper plApplicationEnvironmentMapper;

    @Autowired
    private PlApiMappingStructureMapper plApiMappingStructureMapper;
    
    @Autowired 
    PlExpressApiConfigMapper expressApiConfigMapper;

    
    

    @Override
    public ApiMappingInfoBo getApiMappingInfo(String apiMappingCode) {
    	LambdaQueryWrapper<PlApiMapping> query = Wrappers.lambdaQuery();
    	query.eq(PlApiMapping::getApiMappingCode,apiMappingCode);
    	List<PlApiMapping> list = plApiMappingMapper.selectList(query);
    	return getApiMappingInfo(1l,list.get(0).getId(),new PlApiRequestLog());
    }

	@Override
    public ApiMappingInfoBo getApiMappingInfo(Long companyId, Long apiMappingId,PlApiRequestLog log) {
        ApiMappingInfoBo apiInfo = new ApiMappingInfoBo();
        //获取对接场景信息（来源api，目标api，应用关联明细）
        PlApiMapping apiMapping = plApiMappingMapper.selectById(apiMappingId);
        Assert.notNull(apiMapping,"对接场景ID：" + apiMappingId + "不存在");
        apiInfo.setCompanyId(companyId);
        apiInfo.setApiMappingId(apiMapping.getId());
        apiInfo.setApiMappingName(apiMapping.getApiMappingName());
        apiInfo.setApimappingcode(apiMapping.getApiMappingCode());
        
        //获取来源api基础信息
        PlApibaseinfo sourceApi = plApibaseinfoMapper.selectById(apiMapping.getSourceApiId());
        apiInfo.setSourceJsonType(sourceApi.getApiRequestRequestRootType());
        Long scompanyid = Long.parseLong(Optional.ofNullable(sourceApi.getCompanyId()).orElse("1"));
       
        //获取目标api基础信息
        PlApibaseinfo targetApi = plApibaseinfoMapper.selectById(apiMapping.getTargetApiId());
        apiInfo.setTargetJsonType(targetApi.getApiRequestRequestRootType());
        apiInfo.setTargetJsonTemplate(StringUtils.hasText(targetApi.getApiRequestTemplate()) ? targetApi.getApiRequestTemplate() : "{}");
        apiInfo.setTargetApi(targetApi);
      
        //获取应用关联信息
        PlApplicationLink link = Optional.ofNullable(plApplicationLinkMapper.selectById(apiMapping.getApplicationLinkId())).orElse(new PlApplicationLink());
        apiInfo.setRequestCompanyId(link.getAboveCompanyId());
        apiInfo.setRequestCompanyName(link.getAboveCompanyName());
        apiInfo.setRequestApplicationId(link.getAboveApplicationId());
        apiInfo.setRequestApplicationName(link.getAboveApplicationName());
        apiInfo.setResponseCompanyId(link.getBelowCompanyId());
        apiInfo.setResponseCompanyName(link.getBelowCompanyName());
        apiInfo.setResponseApplicationId(link.getBelowApplicationId());
        apiInfo.setResponseApplicationName(link.getBelowApplicationName());
        //获取应用关联明细信息
        PlApplicationLinkDtl linkDtl = Optional.ofNullable(plApplicationLinkDtlMapper.selectById(apiMapping.getApplicationLinkDtlId())).orElse(new PlApplicationLinkDtl());
        apiInfo.setRequestEnvironmentId(linkDtl.getAboveEnvironmentId());
        apiInfo.setRequestEnvironmentName(linkDtl.getAboveEnvironmentName());
        apiInfo.setResponseEnvironmentId(linkDtl.getBelowEnvironmentId());
        apiInfo.setResponseEnvironmentName(linkDtl.getBelowEnvironmentName());
        //获取来源环境信息
        PlApplicationEnvironment sourceEnvironment = Optional.ofNullable(plApplicationEnvironmentMapper.selectById(linkDtl.getAboveEnvironmentId())).orElse(new PlApplicationEnvironment());
        //设置来源接口地址 sourceEnvironment.basicurl + sourceApi.apiDomail
        apiInfo.setSourceUrl(sourceEnvironment.getBasicurl() + sourceApi.getApiDomail());
        //获取目标环境信息
        PlApplicationEnvironment targetEnvironment = Optional.ofNullable(plApplicationEnvironmentMapper.selectById(linkDtl.getBelowEnvironmentId())).orElse(new PlApplicationEnvironment());
        //设置请求目标接口地址 targetEnvironment.basicurl + targetApi.apiDomail
        if(null == targetApi.getApiDomail()) {
        	apiInfo.setTargetUrl(targetEnvironment.getBasicurl());
        }else {
        	apiInfo.setTargetUrl(targetEnvironment.getBasicurl()+targetApi.getApiDomail());
        }
        
        
        if(apiMapping.getExpresscondition()!=null) {
        	PlExpressApiConfig expressconfig =	expressApiConfigMapper.selectById(apiMapping.getExpresscondition());
        	apiInfo.setExpressconfig(expressconfig);
        }
        
        //记录日志字段
        apiInfo.setLogkey(sourceApi.getLogkey());
        apiInfo.setActiveTarget(apiMapping.getActiveTarget());
       
        
        log.setRequestCompanyId(scompanyid);
        log.setRequestCompanyName("");
        log.setRequestApplicationId(link.getAboveApplicationId());
        log.setRequestApplicationName(link.getAboveApplicationName());
        log.setRequestEnvironmentId(linkDtl.getAboveEnvironmentId());
        log.setRequestEnvironmentName(linkDtl.getAboveEnvironmentName());
        
        log.setSceneId(apiMappingId);
        log.setSceneName(apiMapping.getApiMappingName());
        
        Long tcompanyid = Long.parseLong(Optional.ofNullable(targetApi.getCompanyId()).orElse("1"));
        log.setResponseCompanyId(tcompanyid);
        log.setResponseCompanyName("");
        log.setResponseApplicationId(link.getBelowApplicationId());
        log.setResponseApplicationName(link.getBelowApplicationName());
        log.setResponseEnvironmentId(linkDtl.getBelowEnvironmentId());
        log.setResponseEnvironmentName(linkDtl.getBelowEnvironmentName());
        
        
        log.setRequestInterfaceId(targetApi.getId());
        log.setRequestInterfaceName(targetApi.getApiName());
        log.setRequestIp(targetEnvironment.getBasicurl());
        return apiInfo;
    }

    @Override
    public PlApiMapping getPlApiMappingByApiMappingCode(String apiMappingCode) {
        LambdaQueryWrapper<PlApiMapping> query = Wrappers.lambdaQuery();
        query.eq(PlApiMapping::getApiMappingCode,apiMappingCode);
        List<PlApiMapping> list = plApiMappingMapper.selectList(query);
        return CollectionUtils.isEmpty(list) ? null : list.get(0);
    }

    @Override
    public String convertJson(List<PlApiMappingStructure> structureList, String json) {
        if(json.startsWith("[")){
            return convertJsonArray(structureList,json);
        }else{
            return convertJsonObject(structureList,json);
        }
    }

    @Override
    public String convertJson(List<PlApiMappingStructure> structureList, String json, Map<String, Map<String, Object>> globalMap) {
        return null;
    }

    private String convertJsonObject(List<PlApiMappingStructure> structureList,String json) {
        JSONObject jsonObject = JSONArray.parseObject(json);
        if(jsonObject == null){
            return null;
        }
        //根据场景ID获取报文结构
        Map<Long, List<PlApiMappingStructure>> map = groupPlApiMappingStructure(structureList);
        //如果没有配置报文映射，或没有根节点，直接返回源JSON
        if(map == null || !map.containsKey(-1L)){
            return json;
        }
        return jsonFieldMapping(-1L,jsonObject,map).toJSONString();
    }

    private String convertJsonArray(List<PlApiMappingStructure> structureList, String json) {
        JSONArray jsonArray = JSONArray.parseArray(json);
        if(CollectionUtils.isEmpty(jsonArray)){
            return null;
        }
        //根据场景ID获取报文结构
        Map<Long, List<PlApiMappingStructure>> map = groupPlApiMappingStructure(structureList);
        //如果没有配置报文映射，或没有根节点，直接返回源JSON
        if(map == null || !map.containsKey(-1L)){
            return json;
        }
        JSONArray array = new JSONArray();
        for(int i = 0; i < jsonArray.size(); i++){
            array.add(jsonFieldMapping(-1L,jsonArray.getJSONObject(i),map));
        }
        return array.toJSONString();
    }

    @Override
    public String convertSameStructureJson(SyncRequest request,List<PlApiMappingStructure> structureList) {
        //获取对接场景信息（来源api，目标api，应用关联明细）
        PlApiMapping apiMapping = plApiMappingMapper.selectById(request.getApiMappingId());
        Assert.notNull(apiMapping,"对接场景ID：" + request.getApiMappingId() + "不存在");
        return convertJson(structureList, JSON.toJSONString(request.getData()));
    }

    @Override
    public List<PlApiMappingStructure> getPlApiMappingStructure(Long apiMappingId) {
        LambdaQueryWrapper<PlApiMappingStructure> query = Wrappers.lambdaQuery();
        query.eq(PlApiMappingStructure::getApiMappingId,apiMappingId);
        //根据场景ID获取报文结构
        return plApiMappingStructureMapper.selectList(query);
    }

    /**
     * 获取报文结构映射关系
     * @param structureList
     * @return
     */
    private Map<Long, List<PlApiMappingStructure>> groupPlApiMappingStructure(List<PlApiMappingStructure> structureList){
        if(CollectionUtils.isEmpty(structureList)){
            return null;
        }
        return structureList.stream().collect(Collectors.groupingBy(PlApiMappingStructure::getSourceParentField));
    }

    /**
     * JSON字段映射
     * @param parentId
     * @param jsonObject
     * @param map
     * @return
     */
    private JSONObject jsonFieldMapping(Long parentId,JSONObject jsonObject,Map<Long, List<PlApiMappingStructure>> map){
        if(jsonObject == null){
            return null;
        }
        JSONObject result = new JSONObject();
        List<PlApiMappingStructure> structureList = map.get(parentId);
        for(PlApiMappingStructure s : structureList){
            //获取目标节点，如果为空则取源节点
            String key = StringUtils.hasText(s.getTargetFieldName()) ? s.getTargetFieldName() : s.getSourceFieldName();
            if ("object".equals(s.getSourceFieldType())) {
                //判断是否存在子节点，如果存在继续处理子节点，否则写入对应节点对象
                if(map.containsKey(s.getSourceParentField())){
                    result.put(key,jsonFieldMapping(s.getSourceFieldCode(),jsonObject.getJSONObject(s.getSourceFieldName()),map));
                }else{
                    result.put(key,jsonObject.getJSONObject(s.getSourceFieldName()));
                }
            }else if ("array".equals(s.getSourceFieldType())) {
                //判断是否存在子节点，如果存在继续处理子节点，否则写入对应节点数组
                if(map.containsKey(s.getSourceParentField())){
                    JSONArray array = jsonObject.getJSONArray(s.getSourceFieldName());
                    JSONArray resultArray = new JSONArray();
                    for(int i = 0; i < array.size(); i++){
                        resultArray.add(jsonFieldMapping(s.getSourceParentField(),array.getJSONObject(i),map));
                    }
                    result.put(key,resultArray);
                }else{
                    result.put(key,jsonObject.getJSONArray(s.getSourceFieldName()));
                }
            }else {
                result.put(key,jsonObject.get(s.getSourceFieldName()));
            }
        }
        return result;
    }
}
